﻿/**
 * ...
 * @author alijaya
 */

package homponex.core;

#if flash9
import flash.display.Sprite;
import homponex.events.MouseEvent;
#end

import heox.Rectangle;
import heox.events.PositionEvent;
import heox.events.DimensionEvent;

import homponex.events.EnabledEvent;
import homponex.utils.StringUtils;
import homponex.utils.NameUtils;
import homponex.utils.DynamicUtils;

class Component extends Rectangle
{

	public var name:String;
	
	public var depth(get_depth, null) : Int;
	
	private function get_depth() : Int
	{
		return (parent != null)? parent.depth+1 : 0;
	}
	
	private var style:Dynamic;
	
	#if flash9
	public var view:Sprite;
	
	private var inSprite:Bool;
	private var press:Bool;
	#end
	
	/////////////////////////
	// Hierarcy Properties //
	/////////////////////////
	
	private var _dependency : Component;
	public var dependency(get_dependency, set_dependency) : Component;
	
	private function get_dependency() : Component
	{
		return _dependency;
	}
	
	private function set_dependency(value:Component) : Component
	{
		if(dependency != null) dependency.removeEventListener(EnabledEvent.CUR_ENABLED, curEnabledHandler);
		_dependency = value;
		if(dependency != null) dependency.addEventListener(EnabledEvent.CUR_ENABLED, curEnabledHandler);
		return value;
	}
	
	public var parent(default, null):Panel;
	
	///////////////////////
	// Enable Properties //
	///////////////////////
	
	public var curEnabled(default, null) : Bool;
	
	private var _enabled : Bool;
	public var enabled(get_enabled, set_enabled) : Bool;
	
	private function get_enabled() : Bool
	{
		return _enabled;
	}
	
	private function set_enabled(value:Bool) : Bool
	{
		_enabled = value;
		update_enabled();
		dispatchEvent(new EnabledEvent(EnabledEvent.ENABLED, enabled));
		return value;
	}
	
	///////////////////////////
	// Coordinate Properties //
	///////////////////////////
	
	// Use Percent Or Not //
	
	public var xPercent:Bool;
	public var yPercent:Bool;
	public var widthPercent:Bool;
	public var heightPercent:Bool;
	
	// Percent Coordinate //
	
	private var _xP : Float;
	public var xP(get_xP, set_xP) : Float;
	
	private function get_xP() : Float
	{
		return _xP;
	}
	
	private function set_xP(value:Float) : Float
	{
		_xP = value;
		update_xP();
		return value;
	}
	
	private var _yP : Float;
	public var yP(get_yP, set_yP) : Float;
	
	private function get_yP() : Float
	{
		return _yP;
	}
	
	private function set_yP(value:Float) : Float
	{
		_yP = value;
		update_yP();
		return value;
	}
	
	private var _widthP : Float;
	public var widthP(get_widthP, set_widthP) : Float;
	
	private function get_widthP() : Float
	{
		return _widthP;
	}
	
	private function set_widthP(value:Float) : Float
	{
		_widthP = value;
		update_widthP();
		return value;
	}
	
	private var _heightP : Float;
	public var heightP(get_heightP, set_heightP) : Float;
	
	private function get_heightP() : Float
	{
		return _heightP;
	}
	
	private function set_heightP(value:Float) : Float
	{
		_heightP = value;
		update_heightP();
		return value;
	}
	
	/////////////////
	// Constructor //
	/////////////////
	
	private function new() 
	{
		super();
		name = NameUtils.getName(this);
		style = { };
		#if flash9
		view = new Sprite();
		view.addEventListener(flash.events.MouseEvent.ROLL_OVER, rollOverHandler);
		view.addEventListener(flash.events.MouseEvent.ROLL_OUT, rollOutHandler);
		view.addEventListener(flash.events.MouseEvent.MOUSE_DOWN, mouseDownHandler);
		#end
		fixedX = null;
		fixedY = null;
		fixedWidth = null;
		fixedHeight = null;
		_x = 0;
		_y = 0;
		_width = 0;
		_height = 0;
		_enabled = true;
		curEnabled = true;
	}
	
	public function setStyle(s:Dynamic)
	{
		mergeStyle(s);
	}
	
	private function mergeStyle(s:Dynamic)
	{
		DynamicUtils.mergeDynamic(style, s);
	}
	
	/////////////////////////
	// Coordinate Function //
	/////////////////////////
	
	public function setPercentPos(xPercent:Bool, yPercent:Bool)
	{
		this.xPercent = xPercent;
		this.yPercent = yPercent;
	}
	
	public function setPercentDim(widthPercent:Bool, heightPercent:Bool)
	{
		this.widthPercent = widthPercent;
		this.heightPercent = heightPercent;
	}
	
	public function setPercentPosDim(xPercent:Bool, yPercent:Bool, widthPercent:Bool, heightPercent:Bool)
	{
		setPercentPos(xPercent, yPercent);
		setPercentDim(widthPercent, heightPercent);
	}
	
	public function setPPos(xP:Float, yP:Float)
	{
		this.xP = xP;
		this.yP = yP;
	}
	
	public function setPDim(widthP:Float, heightP:Float)
	{
		this.widthP = widthP;
		this.heightP = heightP;
	}
	
	public function setPPosDim(xP:Float, yP:Float, widthP:Float, heightP:Float)
	{
		setPPos(xP, yP);
		setPDim(widthP, heightP);
	}
	
	///////////////////////
	// Hierarcy Function //
	///////////////////////
	
	public function addTo(p:Panel)
	{
		if (p.existsChild(this))
		{
			if (parent != p)
			{
				parent = p;
				update_added();
				parent.addEventListener(EnabledEvent.CUR_ENABLED, curEnabledHandler);
				parent.addEventListener(DimensionEvent.WIDTH, widthHandler);
				parent.addEventListener(DimensionEvent.HEIGHT, heightHandler);
			}
		} else
		{
			removeFrom();
			parent = p;
			p.addChild(this);
			update_added();
			parent.addEventListener(EnabledEvent.CUR_ENABLED, curEnabledHandler);
		}
	}
	
	public function removeFrom()
	{
		if (parent != null)
		{
			if (parent.existsChild(this))
			{
				var p:Panel = parent;
				parent = null;
				p.removeChild(this);
				update_removed();
				parent.removeEventListener(EnabledEvent.CUR_ENABLED, curEnabledHandler);
			} else
			{
				parent = null;
				update_removed();
				parent.removeEventListener(EnabledEvent.CUR_ENABLED, curEnabledHandler);
			}
		}
	}
	
	///////////////////
	// Enabled Utils //
	///////////////////
	
	private function changeCurEnabled(value:Bool)
	{
		curEnabled = value;
		update_curEnabled();
		dispatchEvent(new EnabledEvent(EnabledEvent.CUR_ENABLED, curEnabled));
	}
	
	private function dpEnabled() : Bool
	{
		var d:Bool = (dependency != null)? dependency.curEnabled : true;
		var p:Bool = (parent != null)? parent.curEnabled : true;
		var b:Bool = (p)? d : false;
		return b;
	}
	
	//////////////////
	// Mouse Action //
	//////////////////
	
	private function click()
	{
		//trace("click");
		update_click();
		dispatchEvent(new MouseEvent(MouseEvent.CLICK));
	}
	
	private function release()
	{
		//trace("release");
		update_release();
		dispatchEvent(new MouseEvent(MouseEvent.RELEASE));
	}
	
	private function over()
	{
		//trace("over");
		update_over();
		dispatchEvent(new MouseEvent(MouseEvent.OVER));
	}
	
	private function out()
	{
		//trace("out");
		update_out();
		dispatchEvent(new MouseEvent(MouseEvent.OUT));
	}
	
	private function down()
	{
		//trace("down");
		update_down();
		dispatchEvent(new MouseEvent(MouseEvent.DOWN));
	}
	
	/////////////////////
	// Update Function //
	/////////////////////
	
	// Update Enable //
	
	private function update_enabled()
	{
		var e:Bool = (dpEnabled())? enabled : false;
		changeCurEnabled(e);
	}
	
	private function update_curEnabled()
	{
		
	}
	
	// Update Coordinate //
	
	private override function update_x()
	{
		#if flash9
		view.x = x;
		#end
	}
	
	private override function update_y()
	{
		#if flash9
		view.y = y;
		#end
	}
	
	private function update_xP()
	{
		if (parent != null)
		{
			var r:Rectangle = parent.rect;
			x = xP * r.width;
		}
	}
	
	private function update_yP()
	{
		if (parent != null)
		{
			var r:Rectangle = parent.rect;
			y = yP * r.height;
		}
	}
	
	private function update_widthP()
	{
		if (parent != null)
		{
			var r:Rectangle = parent.rect;
			width = widthP * r.width;
		}
	}
	
	private function update_heightP()
	{
		if (parent != null)
		{
			var r:Rectangle = parent.rect;
			height = heightP * r.height;
		}
	}
	
	// Update Hierarcy //
	
	private function update_added()
	{
		if (xPercent) update_xP();
		if (yPercent) update_yP();
		if (widthPercent) update_widthP();
		if (heightPercent) update_heightP();
	}
	
	private function update_removed()
	{
		
	}
	
	// Update Mouse Action //
	
	private function update_click()
	{
		
	}
	
	private function update_release()
	{
		
	}
	
	private function update_over()
	{
		
	}
	
	private function update_out()
	{
		
	}
	
	private function update_down()
	{
		
	}
	
	///////////////////
	// Event Handler //
	///////////////////
	
	private function curEnabledHandler(e:EnabledEvent)
	{
		update_enabled();
	}
	
	private function widthHandler(e:DimensionEvent)
	{
		if (xPercent) update_xP();
		if (widthPercent) update_widthP();
	}
	
	private function heightHandler(e:DimensionEvent)
	{
		if (yPercent) update_yP();
		if (heightPercent) update_heightP();
	}
	
	#if flash9
	// Flash Event Handler //
	
	private function rollOverHandler(e:flash.events.MouseEvent)
	{
		inSprite = true;
		if (!press)
		{
			over();
		} else
		{
			update_down();
		}
	}
	
	private function rollOutHandler(e:flash.events.MouseEvent)
	{
		inSprite = false;
		if (!press)
		{
			out();
		} else
		{
			update_over();
		}
	}
	
	private function mouseDownHandler(e:flash.events.MouseEvent)
	{
		press = true;
		down();
		
		view.parent.addEventListener(flash.events.MouseEvent.MOUSE_UP, mouseUpHandler);
	}
	
	private function mouseUpHandler(e:flash.events.MouseEvent)
	{
		press = false;
		if (inSprite)
		{
			click();
		} else
		{
			release();
		}
		view.parent.removeEventListener(flash.events.MouseEvent.MOUSE_UP, mouseUpHandler);
	}
	#end
	
	///////////////////////
	// Get Tree Function //
	///////////////////////
	
	public function getTree(?depth:Int = 0) : String
	{
		var s:String = StringUtils.nt(1, depth) + "---" + name + " (" + ((curEnabled)? "enabled" : "disabled") + ")";
		return s;
	}
}